﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using Microsoft.Phone.Controls;
using System.Device.Location;
using Microsoft.Phone.Controls.Maps;
using System.Windows.Media.Imaging;
using Parking.Bing.Geocode;
using System.Xml;
using System.IO;
using Microsoft.Phone.Controls.Maps.Core;
using Parking.Bing.Route;
using Microsoft.Phone.Controls.Maps.Platform;

namespace Parking
{
    public partial class MainPage : PhoneApplicationPage
    {
        GeoCoordinateWatcher watcher = new GeoCoordinateWatcher();
        public bool user_search = false;
        public bool calculated_route = false;
        public static bool is_authentificated = false;
        public List<ParkingSpot> area_parkings = new List<ParkingSpot>();
        public bool arrived = false;
        Waypoint dest = null;
        ParkingSpot selected_park;

        // Constructor
        public MainPage()
        {
            InitializeComponent();
        }

        private void PhoneApplicationPage_Loaded(object sender, RoutedEventArgs e)
        {
            SettingsFunctions.LoadData();
            if (ApplicationSettings.gps_on)
            {
                try
                {
                    watcher.Start();
                    if (!watcher.Position.Location.IsUnknown)
                    {
                        adress_map.SetView(watcher.Position.Location, 17);

                        string URI = "http://parcari.casa-az.ro/main/get_parking/" + watcher.Position.Location.Latitude + "/" + watcher.Position.Location.Longitude;
                        //string myParameters = "lat=" + watcher.Position.Location.Latitude + "&long=" + watcher.Position.Location.Longitude;

                        WebClient wc = new WebClient();
                        wc.DownloadStringAsync(new Uri(URI, UriKind.Absolute));
                        wc.DownloadStringCompleted += new DownloadStringCompletedEventHandler(wc_DownloadStringCompleted);
                        //wc.Headers[HttpRequestHeader.ContentType] = "application/x-www-form-urlencoded";
                        //wc.UploadStringAsync(new Uri(URI, UriKind.Absolute), "POST", myParameters);
                        //wc.UploadStringCompleted += new UploadStringCompletedEventHandler(wc_UploadStringCompleted);

                        watcher.PositionChanged += new EventHandler<GeoPositionChangedEventArgs<GeoCoordinate>>(watcher_PositionChanged);
                    }
                    else
                    {
                        MessageBox.Show("Can not determine your position. Please check your GPS settings.");
                    }

                }
                catch { }
            }
            else
            {
                MessageBox.Show("The GPS is off. Please turn on GPS from settings menu.");
            }
        }

        void wc_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
        {
            try
            {
                string HttpResult = e.Result;
                HttpResult = HttpResult.Substring(2, HttpResult.Length - 4);
                string[] parkings = HttpResult.Split(new string[] { "},{" }, StringSplitOptions.RemoveEmptyEntries);
                area_parkings.Clear();
                for (int i = 0; i < parkings.Length; i++)
                {
                    string parking = parkings[i];
                    ParkingSpot ps = new ParkingSpot();

                    int start_index = parking.IndexOf("\"id\":\"") + 6;
                    int end_index = parking.Substring(start_index).IndexOf("\",\"");
                    ps.id = Convert.ToInt32(parking.Substring(start_index, end_index));

                    start_index = parking.IndexOf("\"auth_no\":\"") + 11;
                    end_index = parking.Substring(start_index).IndexOf("\",\"");
                    ps.auth_no = parking.Substring(start_index, end_index).Replace("\\/", "/");

                    start_index = parking.IndexOf("\"name\":\"") + 8;
                    end_index = parking.Substring(start_index).IndexOf("\",\"");
                    ps.name = parking.Substring(start_index, end_index);

                    start_index = parking.IndexOf("\"address\":\"") + 11;
                    end_index = parking.Substring(start_index).IndexOf("\",\"");
                    ps.adress = parking.Substring(start_index, end_index);

                    start_index = parking.IndexOf("\"x_coord\":\"") + 11;
                    end_index = parking.Substring(start_index).IndexOf("\",\"");
                    ps.longitude = parking.Substring(start_index, end_index);

                    start_index = parking.IndexOf("\"y_coord\":\"") + 11;
                    end_index = parking.Substring(start_index).IndexOf("\",\"");
                    ps.latitude = parking.Substring(start_index, end_index);

                    start_index = parking.IndexOf("\"available\":\"") + 13;
                    end_index = parking.Substring(start_index).IndexOf("\",\"");
                    ps.available = Convert.ToInt32(parking.Substring(start_index, end_index));

                    start_index = parking.IndexOf("\"cost\":\"") + 8;
                    end_index = parking.Substring(start_index).IndexOf("\"");
                    ps.cost = Convert.ToDouble(parking.Substring(start_index, end_index));

                    area_parkings.Add(ps);
                }
                Refresh_Parkings();
            }
            catch
            {
                MessageBox.Show("Could not determine the parking spots!");
            }
        }

        private void Refresh_Parkings()
        {
            for (int i = 0; i < adress_map.Children.Count; i++)
            {
                if (adress_map.Children[i].GetType() == typeof(MapLayer))
                {
                    MapLayer ml = (MapLayer)adress_map.Children[i];
                    if (ml.Name != "car")
                    {
                        adress_map.Children.RemoveAt(i);
                    }
                }
            }
            foreach (ParkingSpot ps in area_parkings)
            {
                if (ps.available > 0)
                {
                    if (ApplicationSettings.chargeble && !ApplicationSettings.free_of_charge)
                    {
                        if (ps.cost == 0)
                        {
                            continue;
                        }
                    }
                    if (!ApplicationSettings.chargeble && ApplicationSettings.free_of_charge)
                    {
                        if (ps.cost > 0)
                        {
                            continue;
                        }
                    }

                    MapLayer pushPinLayer = new MapLayer();

                    adress_map.Children.Add(pushPinLayer);

                    Pushpin p = new Pushpin();
                    p.Hold += new EventHandler<GestureEventArgs>(p_Hold);
                    p.DoubleTap += new EventHandler<GestureEventArgs>(p_DoubleTap);
                    Bing.Geocode.GeocodeLocation loc = new Bing.Geocode.GeocodeLocation();
                    loc.Latitude = Convert.ToDouble(ps.latitude);
                    loc.Longitude = Convert.ToDouble(ps.longitude);
                    p.Location = loc;
                    p.Width = 32;
                    p.Height = 32;
                    ImageBrush ib = new ImageBrush();
                    if (ps.cost == 0)
                    {
                        ib.ImageSource = new BitmapImage(new Uri("img/free_parking.png", UriKind.Relative));
                    }
                    else
                    {
                        ib.ImageSource = new BitmapImage(new Uri("img/charge_parking.png", UriKind.Relative));
                    }
                    p.Background = ib;
                    p.Tag = ps;
                    pushPinLayer.AddChild(p, loc, PositionOrigin.BottomLeft);
                }
            }
        }

        void p_DoubleTap(object sender, GestureEventArgs e)
        {
            Pushpin p = (Pushpin)sender;

            Waypoint w2 = new Waypoint();
            w2.Location = new Location();
            w2.Location.Latitude = p.Location.Latitude;
            w2.Location.Longitude = p.Location.Longitude;

            Waypoint w1 = new Waypoint();
            w1.Location = watcher.Position.Location;

            selected_park = (ParkingSpot)p.Tag;
            GetRoute(w1, w2);
        }

        void p_Hold(object sender, GestureEventArgs e)
        {
            Pushpin p = (Pushpin)sender;
            ParkingSpot ps = (ParkingSpot)p.Tag;
            p.Width = 300;
            p.Height = 100;
            p.Background = new SolidColorBrush(Colors.Gray);
            string desc = "Parking " + ps.name + "\r\n" + ps.cost + " RON / ora \r\n Locuri disponibile: " + ps.available.ToString();
            p.Content = desc;
        }

        void watcher_PositionChanged(object sender, GeoPositionChangedEventArgs<GeoCoordinate> e)
        {
            var position = watcher.Position;

            for (int i = 0; i < adress_map.Children.Count; i++)
            {
                if (adress_map.Children[i].GetType() == typeof(MapLayer))
                {
                    MapLayer ml = (MapLayer)adress_map.Children[i];
                    if (ml.Name == "car")
                    {
                        adress_map.Children.RemoveAt(i);
                    }
                }
            }

            MapLayer pushPinLayer = new MapLayer();
            pushPinLayer.Name = "car";
            adress_map.Children.Add(pushPinLayer);

            Pushpin p = new Pushpin();
            p.Location = position.Location;

            ImageBrush ib = new ImageBrush();
            ib.ImageSource = new BitmapImage(new Uri("img/car.png", UriKind.Relative));
            p.Width = 45;
            p.Height = 31;
            p.Background = ib;
            pushPinLayer.AddChild(p, position.Location, PositionOrigin.BottomLeft);
            if (!user_search)
            {
                adress_map.SetView(watcher.Position.Location, user_search ? adress_map.ZoomLevel : 17);
            }

            if (dest != null)
            {
                canvas.Visibility = System.Windows.Visibility.Collapsed;
                if (Math.Round(dest.Location.Latitude * 1000) == Math.Round(position.Location.Latitude * 1000) &&
                    Math.Round(dest.Location.Longitude * 1000) == Math.Round(position.Location.Longitude * 1000))
                {
                    if (!arrived)
                    {
                        canvas.Visibility = System.Windows.Visibility.Visible;
                    }
                }
            }
        }

        private void ApplicationBarIconButton_Click(object sender, EventArgs e)
        {
            NavigationService.Navigate(new Uri("/SettingsPage.xaml", UriKind.Relative));
        }

        private void adress_map_MapZoom(object sender, MapZoomEventArgs e)
        {
        }

        private void search_textBox_TextChanged(object sender, TextChangedEventArgs e)
        {

        }

        private void search_textBox_TextInputStart(object sender, TextCompositionEventArgs e)
        {
        }

        private void search_textBox_LostFocus(object sender, RoutedEventArgs e)
        {
            if (search_textBox.Text == "")
            {
                search_textBox.Text = "Search destination";
                search_textBox.FontStyle = FontStyles.Italic;
                search_textBox.Foreground = new SolidColorBrush(Color.FromArgb(32, 0, 0, 0));
            }
        }

        private void search_textBox_GotFocus(object sender, RoutedEventArgs e)
        {
            if (search_textBox.Text == "Search destination")
            {
                search_textBox.Text = "";
                search_textBox.FontStyle = FontStyles.Normal;
                search_textBox.Foreground = new SolidColorBrush(Colors.Black);
            }
        }

        private void button_search_Click(object sender, RoutedEventArgs e)
        {
            user_search = true;
            GetLocation("Romania, " + search_textBox.Text.Trim());
        }

        private void GetLocation(string adress)
        {
            try
            {
                GeocodeRequest geo_request = new GeocodeRequest();
                geo_request.Credentials = new Microsoft.Phone.Controls.Maps.Credentials();
                geo_request.Credentials.ApplicationId = "Ahk_BZ2QFotkKjniIQ4nY-H7c_f40q69EfoOSmwBjM0bCL6tdbq89gDY81b6EkMG";
                geo_request.Query = adress;
                Bing.Geocode.GeocodeServiceClient geocodeServiceClient = new GeocodeServiceClient("BasicHttpBinding_IGeocodeService");
                geocodeServiceClient.GeocodeCompleted += new EventHandler<GeocodeCompletedEventArgs>(geocodeServiceClient_GeocodeCompleted);
                geocodeServiceClient.GeocodeAsync(geo_request);
            }
            catch
            {
                MessageBox.Show("Error in location search.");
            }
        }

        void geocodeServiceClient_GeocodeCompleted(object sender, GeocodeCompletedEventArgs e)
        {
            GeocodeResponse resp = e.Result;
            foreach (var res in resp.Results)
            {
                foreach (var loc in res.Locations)
                {
                    adress_map.SetView(loc, 17);

                    string URI = "http://parcari.casa-az.ro/main/get_parking/" + loc.Latitude + "/" + loc.Longitude;

                    WebClient wc = new WebClient();
                    wc.DownloadStringAsync(new Uri(URI, UriKind.Absolute));
                    wc.DownloadStringCompleted += new DownloadStringCompletedEventHandler(wc_DownloadStringCompleted);
                }
            }
        }

        private void ApplicationBarMenuItem_Click(object sender, EventArgs e)
        {
            NavigationService.Navigate(new Uri("/LoginPage.xaml", UriKind.Relative));
        }

        private void ApplicationBarMenuItem_Click_1(object sender, EventArgs e)
        {
            NavigationService.Navigate(new Uri("/CreateAccPage.xaml", UriKind.Relative));
        }

        private void adress_map_GotFocus(object sender, RoutedEventArgs e)
        {
            user_search = true;
        }

        private void ApplicationBarIconButton_Click_1(object sender, EventArgs e)
        {
            if (!watcher.Position.Location.IsUnknown)
            {
                string URI = "http://parcari.casa-az.ro/main/get_parking/" + watcher.Position.Location.Latitude + "/" + watcher.Position.Location.Longitude;

                WebClient wc = new WebClient();
                wc.DownloadStringAsync(new Uri(URI, UriKind.Absolute));
                wc.DownloadStringCompleted += new DownloadStringCompletedEventHandler(wc_DownloadStringCompleted);
            }
            calculated_route = false;
        }

        private void GetRoute(Waypoint l1, Waypoint l2)
        {
            try
            {
                // Create the service variable and set the callback method using the CalculateRouteCompleted property.
                RouteServiceClient routeService = new RouteServiceClient("BasicHttpBinding_IRouteService");
                routeService.CalculateRouteCompleted += new EventHandler<CalculateRouteCompletedEventArgs>(routeServiceClient_CalculateRouteCompleted);

                // Set the token.
                RouteRequest routeRequest = new RouteRequest();
                routeRequest.Credentials = new Credentials();
                routeRequest.Credentials.ApplicationId = ((ApplicationIdCredentialsProvider)adress_map.CredentialsProvider).ApplicationId;

                // Return the route points so the route can be drawn.
                routeRequest.Options = new RouteOptions();
                routeRequest.Options.RoutePathType = RoutePathType.Points;
                routeRequest.Options.Mode = TravelMode.Driving;
                routeRequest.Options.TrafficUsage = TrafficUsage.None;

                // Set the waypoints of the route to be calculated using the Geocode Service results stored in the geocodeResults variable.
                routeRequest.Waypoints = new System.Collections.ObjectModel.ObservableCollection<Waypoint>();

                routeRequest.Waypoints.Add(l1);
                routeRequest.Waypoints.Add(l2);

                // Make the CalculateRoute asnychronous request.
                TimeSpan timeout = new TimeSpan(0, 0, 15);
                routeService.Endpoint.Binding.ReceiveTimeout = timeout;
                routeService.Endpoint.Binding.SendTimeout = timeout;
                routeService.Endpoint.Binding.OpenTimeout = timeout;

                routeService.CalculateRouteAsync(routeRequest);

                dest = l2;
            }
            catch
            {
            }
        }

        void routeServiceClient_CalculateRouteCompleted(object sender, CalculateRouteCompletedEventArgs e)
        {
            // If the route calculate was a success and contains a route, then draw the route on the map.
            if ((e.Result.ResponseSummary.StatusCode == Bing.Route.ResponseStatusCode.Success) & (e.Result.Result.Legs.Count != 0))
            {
                // Set properties of the route line you want to draw.
                Color routeColor = Colors.Orange;
                SolidColorBrush routeBrush = new SolidColorBrush(routeColor);
                MapPolyline routeLine = new MapPolyline();
                routeLine.Locations = new LocationCollection();
                routeLine.Stroke = routeBrush;
                routeLine.StrokeThickness = 5;

                // Retrieve the route points that define the shape of the route.
                foreach (Location p in e.Result.Result.RoutePath.Points)
                {
                    Location l = new Location();
                    l.Latitude = p.Latitude;
                    l.Longitude = p.Longitude;
                    routeLine.Locations.Add(l);
                }

                // Add a map layer in which to draw the route.
                MapLayer myRouteLayer = new MapLayer();
                for (int i = 0; i < adress_map.Children.Count; i++)
                {
                    if (adress_map.Children[i].GetType() == typeof(MapLayer))
                    {
                        adress_map.Children.RemoveAt(i);
                    }
                }

                adress_map.Children.Add(myRouteLayer);

                // Add the route line to the new layer.
                myRouteLayer.Children.Add(routeLine);
            }
            calculated_route = true;
        }

        private void ApplicationBarIconButton_Click_2(object sender, EventArgs e)
        {
            if (calculated_route)
            {
                user_search = false;
            }
            else
            {
                double min_distance = double.MaxValue;
                Location loc = watcher.Position.Location;
                Location dest = new Location();

                foreach (ParkingSpot ps in area_parkings)
                {
                    if (ApplicationSettings.is_nearest_planning == false && ps.available < 10)
                    {
                        continue;
                    }
                    var dLat = this.ToRadian(Convert.ToDouble(ps.latitude) - loc.Latitude);
                    var dLon = this.ToRadian(Convert.ToDouble(ps.longitude) - loc.Longitude);
                    var a = Math.Sin(dLat / 2) * Math.Sin(dLat / 2) +
                            Math.Cos(this.ToRadian(loc.Latitude)) * Math.Cos(this.ToRadian(Convert.ToDouble(ps.latitude))) *
                            Math.Sin(dLon / 2) * Math.Sin(dLon / 2);
                    var c = 2 * Math.Asin(Math.Min(1, Math.Sqrt(a)));
                    var d = 6371 * c;

                    if (d < min_distance)
                    {
                        min_distance = d;
                        dest.Latitude = Convert.ToDouble(ps.latitude);
                        dest.Longitude = Convert.ToDouble(ps.longitude);
                        selected_park = ps;
                    }
                }
                calculated_route = false;
                Waypoint w1 = new Waypoint();
                w1.Location = watcher.Position.Location;

                Waypoint w2 = new Waypoint();
                w2.Location = dest;
                GetRoute(w1, w2);
            }
            arrived = false;
        }

        private double ToRadian(double val)
        {
            return (Math.PI / 180) * val;
        }

        private void park_button_Click(object sender, RoutedEventArgs e)
        {
            arrived = true;
            string URI = "http://parcari.casa-az.ro/main/update_stay/" + selected_park.id;

            WebClient wc = new WebClient();
            wc.DownloadStringAsync(new Uri(URI, UriKind.Absolute));
            wc.DownloadStringCompleted += new DownloadStringCompletedEventHandler(wc_DownloadStringCompleted1);

            canvas.Visibility = System.Windows.Visibility.Collapsed;
        }

        private void taken_button_Click(object sender, RoutedEventArgs e)
        {
            arrived = true;
            string URI = "http://parcari.casa-az.ro/main/update_stay/" + selected_park.id;

            WebClient wc = new WebClient();
            wc.DownloadStringAsync(new Uri(URI, UriKind.Absolute));
            wc.DownloadStringCompleted += new DownloadStringCompletedEventHandler(wc_DownloadStringCompleted1);

            canvas.Visibility = System.Windows.Visibility.Collapsed;
            ApplicationBarIconButton_Click_1(null, null);
        }

        void wc_DownloadStringCompleted1(object sender, DownloadStringCompletedEventArgs e)
        {
        }
    }
}